from rest_framework import viewsets, status, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from django.db.models import Q
from django.http import HttpResponse, Http404
from django.shortcuts import get_object_or_404
from django.utils import timezone
import mimetypes
import os
import logging
from .models import ExperimentStatistics, ExperimentAttachment
from .serializers import (
    ExperimentStatisticsSerializer,
    ExperimentStatisticsCreateSerializer,
    ExperimentAttachmentSerializer
)

logger = logging.getLogger(__name__)

class ExperimentStatisticsViewSet(viewsets.ModelViewSet):
    """试验统计视图集"""
    
    queryset = ExperimentStatistics.objects.all()
    serializer_class = ExperimentStatisticsSerializer
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    
    # 过滤字段
    filterset_fields = {
        'experiment_number': ['exact', 'icontains'],
        'experiment_name': ['exact', 'icontains'],
        'test_items': ['exact', 'icontains'],
        'test_equipment': ['exact', 'icontains'],
        'experiment_commander': ['exact', 'icontains'],
        'is_external_collaboration': ['exact'],
        'test_company': ['exact', 'icontains'],
        'participant_name': ['exact', 'icontains'],
        'product_entry_date': ['exact', 'gte', 'lte'],
        'test_start_date': ['exact', 'gte', 'lte'],
        'test_end_date': ['exact', 'gte', 'lte'],
        'product_exit_date': ['exact', 'gte', 'lte'],
        'photo_uploaded': ['exact'],
        'created_at': ['exact', 'gte', 'lte'],
    }
    
    # 搜索字段
    search_fields = [
        'experiment_number',
        'experiment_name',
        'test_items',
        'test_equipment',
        'experiment_commander',
        'participants',
        'test_company',
        'participant_name',
        'summary_report'
    ]
    
    # 排序字段
    ordering_fields = [
        'experiment_number',
        'experiment_name',
        'test_start_date',
        'test_end_date',
        'created_at',
        'updated_at'
    ]
    
    ordering = ['created_at']  # 默认按创建时间正序，新数据显示在后面
    
    def get_serializer_class(self):
        """根据动作选择序列化器"""
        # 统一使用ExperimentStatisticsSerializer，它已经处理了字段映射
        return ExperimentStatisticsSerializer
    
    def create(self, request, *args, **kwargs):
        """创建试验记录"""
        try:
            logger.info(f"接收到的数据: {request.data}")
            serializer = self.get_serializer(data=request.data)
            if not serializer.is_valid():
                logger.error(f"序列化器验证失败: {serializer.errors}")
                return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
            
            self.perform_create(serializer)
            headers = self.get_success_headers(serializer.data)
            return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
        except Exception as e:
            logger.error(f"创建试验记录时发生错误: {str(e)}")
            return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    def get_queryset(self):
        """获取查询集"""
        queryset = ExperimentStatistics.objects.all()
        
        # 支持按试验分类过滤（前端的selectedCategory）
        category = self.request.query_params.get('category', None)
        if category and category != '全部':
            # 这里可以根据实际的分类逻辑进行过滤
            # 目前前端有：全部、协外试验、内部试验等分类
            if category == '协外试验':
                queryset = queryset.filter(is_external_collaboration='是')
            elif category == '内部试验':
                queryset = queryset.filter(is_external_collaboration='否')
        
        return queryset
    
    @action(detail=False, methods=['get'])
    def statistics(self, request):
        """获取统计信息"""
        queryset = self.get_queryset()
        
        total_count = queryset.count()
        external_count = queryset.filter(is_external_collaboration='是').count()
        internal_count = queryset.filter(is_external_collaboration='否').count()
        photo_uploaded_count = queryset.filter(photo_uploaded='是').count()
        
        return Response({
            'total_count': total_count,
            'external_count': external_count,
            'internal_count': internal_count,
            'photo_uploaded_count': photo_uploaded_count,
            'photo_upload_rate': round(photo_uploaded_count / total_count * 100, 2) if total_count > 0 else 0
        })
    
    @action(detail=False, methods=['get'])
    def categories(self, request):
        """获取试验分类列表"""
        categories = [
            {'value': '全部', 'label': '全部'},
            {'value': '协外试验', 'label': '协外试验'},
            {'value': '内部试验', 'label': '内部试验'},
        ]
        return Response(categories)
    
    @action(detail=True, methods=['post'])
    def add_attachment(self, request, pk=None):
        """为试验添加附件"""
        experiment = self.get_object()
        
        # 检查是否有文件上传
        if 'file' in request.FILES:
            uploaded_file = request.FILES['file']
            
            # 创建附件记录
            attachment = ExperimentAttachment.objects.create(
                experiment=experiment,
                name=uploaded_file.name,
                size=uploaded_file.size,
                file_type=uploaded_file.content_type,
                content=uploaded_file.read(),  # 保存文件内容
                upload_time=timezone.now()
            )
            
            serializer = ExperimentAttachmentSerializer(attachment)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            # 如果没有文件，使用原来的方式（仅保存元数据）
            serializer = ExperimentAttachmentSerializer(data=request.data)
            
            if serializer.is_valid():
                serializer.save(experiment=experiment)
                return Response(serializer.data, status=status.HTTP_201_CREATED)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    @action(detail=True, methods=['get'])
    def attachments(self, request, pk=None):
        """获取试验的所有附件"""
        experiment = self.get_object()
        attachments = experiment.attachments.all()
        serializer = ExperimentAttachmentSerializer(attachments, many=True)
        return Response(serializer.data)

class ExperimentAttachmentViewSet(viewsets.ModelViewSet):
    """试验附件视图集"""
    
    queryset = ExperimentAttachment.objects.all()
    serializer_class = ExperimentAttachmentSerializer
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    
    filterset_fields = {
        'experiment': ['exact'],
        'name': ['exact', 'icontains'],
        'file_type': ['exact', 'icontains'],
        'upload_time': ['exact', 'gte', 'lte'],
    }
    
    search_fields = ['name', 'file_type']
    ordering_fields = ['name', 'size', 'upload_time']
    ordering = ['-upload_time']
    
    @action(detail=True, methods=['get'])
    def download(self, request, pk=None):
        """下载附件"""
        attachment = get_object_or_404(ExperimentAttachment, pk=pk)
        
        # 这里假设附件内容存储在content字段中
        # 如果是文件路径，需要读取文件内容
        try:
            # 获取文件内容（这里需要根据实际存储方式调整）
            file_content = attachment.content if hasattr(attachment, 'content') else b''
            
            # 设置响应头
            response = HttpResponse(file_content)
            response['Content-Type'] = attachment.file_type or 'application/octet-stream'
            response['Content-Disposition'] = f'attachment; filename="{attachment.name}"'
            response['Content-Length'] = len(file_content)
            
            return response
        except Exception as e:
            logger.error(f"下载附件失败: {str(e)}")
            return Response({'error': '文件下载失败'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    
    @action(detail=True, methods=['get'])
    def preview(self, request, pk=None):
        """预览附件"""
        attachment = get_object_or_404(ExperimentAttachment, pk=pk)
        
        try:
            # 获取文件内容
            file_content = attachment.content if hasattr(attachment, 'content') else b''
            
            # 如果file_content是memoryview对象，转换为bytes
            if isinstance(file_content, memoryview):
                file_content = file_content.tobytes()
            
            # 根据文件类型设置响应
            content_type = attachment.file_type or 'application/octet-stream'
            
            # 对于可预览的文件类型，设置inline显示
            if content_type.startswith(('image/', 'application/pdf')):
                response = HttpResponse(file_content, content_type=content_type)
                response['Content-Disposition'] = f'inline; filename="{attachment.name}"'
            elif content_type.startswith('text/') or attachment.name.lower().endswith('.txt'):
                # 处理文本文件的编码问题
                try:
                    # 尝试多种编码方式解码文本文件
                    text_content = None
                    encodings = ['utf-8', 'gbk', 'gb2312', 'big5', 'latin1']
                    
                    for encoding in encodings:
                        try:
                            text_content = file_content.decode(encoding)
                            break
                        except UnicodeDecodeError:
                            continue
                    
                    if text_content is None:
                        # 如果所有编码都失败，使用utf-8并忽略错误
                        text_content = file_content.decode('utf-8', errors='ignore')
                    
                    # 返回UTF-8编码的文本内容
                    response = HttpResponse(text_content.encode('utf-8'), content_type='text/plain; charset=utf-8')
                    response['Content-Disposition'] = f'inline; filename="{attachment.name}"'
                except Exception as decode_error:
                    logger.error(f"文本文件编码转换失败: {str(decode_error)}")
                    return Response({'error': '文本文件编码转换失败'}, status=status.HTTP_400_BAD_REQUEST)
            else:
                # 不支持预览的文件类型，返回错误信息
                return Response({'error': '该文件类型不支持预览'}, status=status.HTTP_400_BAD_REQUEST)
            
            return response
        except Exception as e:
            logger.error(f"预览附件失败: {str(e)}")
            return Response({'error': '文件预览失败'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
